home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Info / For Developers / GhostScript 5.10 / MacGS-510 / files / font2c.ps < prev    next >
Text File  |  1995-11-21  |  20KB  |  687 lines

  1. %    Copyright (C) 1992, 1993, 1994, 1995 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % font2c.ps
  16. % Write out a PostScript Type 0 or Type 1 font as C code
  17. % that can be linked with the interpreter.
  18. % This even works on protected fonts, if you use the -dWRITESYSTEMDICT
  19. % switch in the command line.  The code is reentrant and location-
  20. % independent and has no external references, so it can be put into
  21. % a sharable library even on VMS.
  22.  
  23. % Define the maximum string length that all compilers will accept.
  24. % This must be approximately
  25. %    min(max line length, max string literal length) / 4 - 5.
  26.  
  27. /font2cdict 100 dict dup begin
  28.  
  29. /max_wcs 50 def
  30.  
  31. % Define a temporary file for writing out procedures.
  32. /wtempname (_.tmp) def
  33.  
  34. % ------ Protection utilities ------ %
  35.  
  36. % Protection values are represented by a mask:
  37. /a_noaccess 0 def
  38. /a_executeonly 1 def
  39. /a_readonly 3 def
  40. /a_all 7 def
  41. /prot_names
  42.  [ (0) (a_execute) null (a_readonly) null null null (a_all)
  43.  ] def
  44. /prot_opers
  45.  [ {noaccess} {executeonly} {} {readonly} {} {} {} {}
  46.  ] def
  47.  
  48. % Get the protection of an object.
  49.    /getpa
  50.     { dup wcheck
  51.        { pop a_all }
  52.        {    % Check for executeonly or noaccess objects in protected.
  53.          dup protected exch known
  54.       { protected exch get }
  55.       { pop a_readonly }
  56.      ifelse
  57.        }
  58.       ifelse
  59.     } bind def
  60.  
  61. % Get the protection appropriate for (all the) values in a dictionary.
  62.    /getva
  63.     { a_noaccess exch
  64.        { exch pop
  65.          dup type dup /stringtype eq 1 index /arraytype eq or
  66.      exch /packedarraytype eq or
  67.       { getpa a_readonly and or }
  68.       { pop pop a_all exit }
  69.      ifelse
  70.        }
  71.       forall
  72.     } bind def
  73.  
  74. % Keep track of executeonly and noaccess objects,
  75. % but don't let the protection actually take effect.
  76. .currentglobal
  77. false .setglobal    % so protected can reference local objs
  78. /protected        % do first so // will work
  79.   systemdict wcheck { 1500 dict } { 1 dict } ifelse
  80. def
  81. systemdict wcheck not
  82.  { (Warning: you will not be able to convert protected fonts.\n) print
  83.    (If you need to convert a protected font, please\n) print
  84.    (restart the program and specify the -dWRITESYSTEMDICT switch.\n) print
  85.    flush
  86.    (%end) .skipeof
  87.  }
  88. if
  89. userdict begin
  90.   /executeonly
  91.    { dup //protected exch //a_executeonly put readonly
  92.    } bind def
  93.   /noaccess
  94.    { dup //protected exch //a_noaccess put readonly
  95.    } bind def
  96. end
  97. true .setglobal
  98. systemdict begin
  99.   /executeonly
  100.    { userdict /executeonly get exec
  101.    } bind odef
  102.   /noaccess
  103.    { userdict /noaccess get exec
  104.    } bind odef
  105. end
  106. %end
  107. .setglobal
  108.  
  109. % ------ Output utilities ------ %
  110.  
  111. % By convention, the output file is named cfile.
  112.  
  113. % Define some utilities for writing the output file.
  114.    /wtstring 100 string def
  115.    /wb {cfile exch write} bind def
  116.    /ws {cfile exch writestring} bind def
  117.    /wl {ws (\n) ws} bind def
  118.    /wt {wtstring cvs ws} bind def
  119.  
  120. % Write a C string.  Some compilers have unreasonably small limits on
  121. % the length of a string literal or the length of a line, so every place
  122. % that uses wcs must either know that the string is short,
  123. % or be prepared to use wcca instead.
  124.    /wbx
  125.     { 8#1000 add 8 (0000) cvrs dup 0 (\\) 0 get put ws
  126.     } bind def
  127.    /wcst
  128.     [
  129.       32 { /wbx load } repeat
  130.       95 { /wb load } repeat
  131.       129 { /wbx load } repeat
  132.     ] def
  133.    ("\\) { wcst exch { (\\) ws wb } put } forall
  134.    /wcs
  135.     { (") ws { dup wcst exch get exec } forall (") ws
  136.     } bind def
  137.    /can_wcs    % Test if can use wcs
  138.     { length max_wcs le
  139.     } bind def
  140.    /wncs    % name -> C string
  141.     { wtstring cvs wcs
  142.     } bind def
  143. % Write a C string as an array of character values.
  144. % We only need this because of line and literal length limitations.
  145.    /wca        % <string> <prefix> <suffix> wca -
  146.     { 0 4 -2 roll exch
  147.        {    % Stack: suffix n prefix char
  148.      exch ws
  149.      exch dup 19 ge { () wl pop 0 } if 1 add
  150.      exch dup 32 ge 1 index 126 le and
  151.       { 39 wb dup 39 eq 1 index 92 eq or { 92 wb } if wb 39 wb }
  152.       { wt }
  153.      ifelse (,)
  154.        } forall
  155.       pop pop ws
  156.     } bind def
  157.    /wcca    % <string> wcca -
  158.     { ({\n) (}) wca
  159.     } bind def
  160.  
  161. % Write object protection attributes.  Note that dictionaries and arrays are
  162. % the only objects that can be writable.
  163.    /wpa
  164.     { dup xcheck { (a_executable|) ws } if
  165.       dup type dup /dicttype eq exch /arraytype eq or
  166.        { getpa }
  167.        { getpa a_readonly and }
  168.       ifelse prot_names exch get ws
  169.     } bind def
  170.    /wva
  171.     { getva prot_names exch get ws
  172.     } bind def
  173.  
  174. % ------ Object writing ------ %
  175.  
  176.    /wnstring 128 string def
  177.  
  178. % Convert an object to a string to be scanned at a later time.
  179.    /cvos        % <obj> cvos <string>
  180.     {        % We'd like to use == and write directly to a string,
  181.         % but we can't do the former because of operators,
  182.         % and we can't do the latter because we can't predict
  183.         % how long the string would have to be....
  184.      wtempname (w) file dup 3 -1 roll wproc closefile
  185.      wtempname status pop pop pop exch pop string
  186.      wtempname (r) file dup 3 -1 roll readstring pop exch closefile
  187.     } bind def
  188.  
  189. % Write a string/name or null as an element of a string/name/null array.
  190. % Convert any other kind of value to a token to be read back in.
  191.    /wsn
  192.     { dup null eq
  193.        { pop (\t255,255,) wl
  194.        }
  195.        { dup type /nametype eq { wnstring cvs } if
  196.      dup type /stringtype ne { cvos (255,) ws } if
  197.      dup length 256 idiv wt (,) ws
  198.      dup length 256 mod wt
  199.      (,) (,\n) wca
  200.        }
  201.       ifelse
  202.     } bind def
  203. % Write a packed string/name/null array.
  204.    /wsna    % <name> <(string|name|null)*> wsna -
  205.     { (\tstatic const char ) ws exch wt ([] = {) wl
  206.       { wsn } forall
  207.       (\t0\n};) wl
  208.     } bind def
  209.  
  210. % Write a number or an array of numbers, as refs.
  211. /isnumber
  212.  { type dup /integertype eq exch /realtype eq or
  213.  } bind def
  214. /wnums
  215.  { dup isnumber
  216.     { (real_v\() ws wt (\),) ws }
  217.     { { wnums } forall }
  218.    ifelse
  219.  } bind def
  220.  
  221. % Test whether a procedure or unusual array can be written (printed).
  222. /iswx 4 dict dup begin
  223.   /arraytype { { iswproc } isall } def
  224.   /nametype { pop true } def
  225.   /operatortype { pop true } def    % assume it has been bound in
  226.   /packedarraytype /arraytype load def
  227. end def
  228. /iswnx 6 dict dup begin
  229.   /arraytype { { iswproc } isall } def
  230.   /integertype { pop true } def
  231.   /nametype { pop true } def
  232.   /realtype { pop true } def
  233.   /stringtype { pop true } def
  234.   /packedarraytype /arraytype load def
  235. end def
  236. /iswproc    % <obj> iswproc <bool>
  237.  { dup xcheck { iswx } { iswnx } ifelse
  238.    1 index type .knownget { exec } { pop false } ifelse
  239.  } bind def
  240.  
  241. % Write a printable procedure (one for which iswproc returns true).
  242. /wproca 3 dict dup begin
  243.   /arraytype
  244.    { 1 index ({) writestring
  245.       { 1 index ( ) writestring 1 index exch wproc } forall
  246.      (}) writestring
  247.    } bind def
  248.   /packedarraytype /arraytype load def
  249.   /operatortype { .writecvs } bind def    % assume binding would work
  250. end def
  251. /wproc        % <file> <proc> wproc -
  252.  { dup type wproca exch .knownget { exec } { write==only } ifelse
  253.  } bind def
  254.  
  255. % Write a named object.  Return true if this was possible.
  256. % Legal types are: boolean, integer, name, real, string,
  257. % array of (integer, integer+real, name, null+string),
  258. % and certain procedures and other arrays (see iswproc above).
  259. % All other objects are either handled specially or ignored.
  260.    /isall    % <array> <proc> isall <bool>
  261.     { true 3 -1 roll
  262.        { 2 index exec not { pop false exit } if }
  263.       forall exch pop
  264.     } bind def
  265.    /wott 8 dict dup begin
  266.       /arraytype
  267.        { woatt
  268.           { aload pop 2 index 2 index exec
  269.          { exch pop exec exit }
  270.          { pop pop }
  271.         ifelse
  272.       }
  273.      forall
  274.        } bind def
  275.       /booleantype
  276.        { { (\tmake_true\(&) } { (\tmake_false\(&) } ifelse ws
  277.          wt (\);) wl true
  278.        } bind def
  279.       /integertype
  280.        { (\tmake_int\(&) ws exch wt (, ) ws
  281.          wt (\);) wl true
  282.        } bind def
  283.       /nametype
  284.        { (\tcode = (*pprocs->name_create)\(&) ws exch wt
  285.          (, ) ws wnstring cvs wcs    % OK, names are short
  286.      (\);) wl
  287.      (\tif ( code < 0 ) return code;) wl
  288.      true
  289.        } bind def
  290.       /packedarraytype
  291.     /arraytype load def
  292.       /realtype
  293.        { (\tmake_real\(&) ws exch wt (, ) ws
  294.          wt (\);) wl true
  295.        } bind def
  296.       /stringtype
  297.        { ({\tstatic const char s_[] = ) ws
  298.          dup dup can_wcs { wcs } { wcca } ifelse
  299.      (;) wl
  300.      (\tmake_const_string\(&) ws exch wt
  301.      (, a_readonly, ) ws length wt (, (const byte *)s_\);) wl
  302.      (}) wl true
  303.        } bind def
  304.    end def
  305. % Write some other kind of object, if known.
  306.    /wother
  307.     { dup otherobjs exch known
  308.        { otherobjs exch get (\t) ws exch wt ( = ) ws wt (;) wl true }
  309.        { pop pop false }
  310.       ifelse
  311.     } bind def
  312. % Top-level procedure.
  313.    /wo        % name obj -> OK
  314.     { dup type wott exch .knownget { exec } { wother } ifelse
  315.     } bind def
  316.  
  317. % Write an array (called by wo).
  318.    /wap        % <name> <array> wap -
  319.     { dup xcheck not 1 index wcheck not and 1 index rcheck and
  320.        { pop pop }
  321.        { (\tr_set_attrs\(&) ws exch wt (, ) ws wpa (\);) wl }
  322.       ifelse
  323.     } bind def
  324.    /wnuma    % <name> <array> <element_C_type> <<type>_v> wnuma -
  325.     { 2 index wcheck
  326.        {    % Allocate an array and copy the values into it.
  327.         % We can't define new callback procedures, so we must
  328.         % do this the hard way.
  329.      pop pop
  330.      ({\tstatic const byte z_[) ws dup length 1 .max 2 mul wt
  331.      (] = {0}; ref r_;) wl
  332.      (\tcode = (*pprocs->string_array_create)\(&r_, z_, ) ws
  333.      dup length wt (, 0\);) wl
  334.      (\tif ( code < 0 ) return code;) wl
  335.      (\tr_set_attrs\(&r_, ) ws dup wpa (\);) wl
  336.      (\t) ws exch wt ( = r_;) wl
  337.      0 1 2 index length 1 sub
  338.       { 2 copy get
  339.         % Stack: array index value
  340.         dup type /integertype eq { (\tmake_int) } { (\tmake_real) } ifelse
  341.         ws (_new\(&r_.value.refs[) ws exch wt
  342.         (], ) ws wt (\);) wl
  343.       }
  344.      for pop
  345.        }
  346.        { ({\tstatic const ref_\() ws exch ws
  347.      (\) a_[] = {) wl exch
  348.      dup length 0 eq
  349.       { (\t) ws 1 index ws (\(0\)) wl
  350.       }
  351.       { dup
  352.          { (\t) ws 2 index ws (\() ws wt (\),) wl
  353.          } forall
  354.       }
  355.      ifelse exch pop
  356.      (\t};) wl
  357.      (\tmake_const_array\(&) ws exch wt
  358.          (, avm_foreign|) ws dup wpa (, ) ws length wt
  359.          (, (const ref *)a_\);) wl
  360.        }
  361.       ifelse
  362.       (}) wl
  363.     } bind def
  364.    /woatt [
  365.     % Integers
  366.      { { { type /integertype eq } isall }
  367.        { (long) (integer_v) wnuma true }
  368.      }
  369.     % Integers + reals
  370.      { { { type dup /integertype eq exch /realtype eq or } isall }
  371.        { (float) (real_v) wnuma true }
  372.      }
  373.     % Strings + nulls
  374.      { { { type dup /nulltype eq exch /stringtype eq or } isall }
  375.        { ({) ws dup (sa_) exch wsna
  376.      (\tcode = (*pprocs->string_array_create)\(&) ws exch wt
  377.      (, sa_, ) ws dup length wt (, ) ws wpa (\);) wl
  378.      (\tif ( code < 0 ) return code;) wl
  379.      (}) wl true
  380.        }
  381.      }
  382.     % Names
  383.      { { { type /nametype eq } isall }
  384.        { ({) ws dup (na_) exch wsna
  385.      (\tcode = (*pprocs->name_array_create)\(&) ws 1 index wt
  386.      (, na_, ) ws dup length wt (\);) wl
  387.      (\tif ( code < 0 ) return code;) wl
  388.      wap (}) wl true
  389.        }
  390.      }
  391.     % Procedure
  392.      { { iswproc }
  393.        { dup cvos
  394.         % Stack: name proc string
  395.      ({\tstatic const char s_[] = ) ws
  396.          dup dup can_wcs { wcs } { wcca } ifelse
  397.      (;) wl
  398.      (\tcode = (*pprocs->ref_from_string)\(&) ws 2 index wt
  399.      (, s_, ) ws length wt (\);) wl
  400.      (\tif ( code < 0 ) return code;) wl
  401.      wap (}) wl true
  402.      wtempname deletefile
  403.        }
  404.      }
  405.     % Default
  406.      { { pop true }
  407.        { wother }
  408.      }
  409.    ] def
  410.  
  411. % Write a named dictionary.  We assume the ref is already declared.
  412.    /wd        % <name> <dict> <extra> wd -
  413.     { 3 1 roll
  414.       ({) ws
  415.       (\tref v_[) ws dup length wt (];) wl
  416.       dup [ exch
  417.        { counttomark 2 sub wtstring cvs
  418.          (v_[) exch concatstrings (]) concatstrings exch wo not
  419.           { (Skipping ) print ==only (....\n) print }
  420.      if
  421.        } forall
  422.       ]
  423.         % Stack: array of keys (names)
  424.       ({) ws dup (str_keys_) exch wsna
  425.       (\tstatic const cfont_dict_keys keys_ =) wl
  426.       (\t { 0, 0, ) ws length wt (, ) ws 3 -1 roll wt (, ) ws
  427.       dup wpa (, ) ws dup wva ( };) wl pop
  428.       (\tcode = \(*pprocs->ref_dict_create\)\(&) ws wt
  429.       (, &keys_, str_keys_, v_\);) wl
  430.       (\tif ( code < 0 ) return code;) wl
  431.       (}) wl
  432.       (}) wl
  433.     } bind def
  434.  
  435. % Write character dictionary keys.
  436. % We save a lot of space by abbreviating keys which appear in
  437. % StandardEncoding or ISOLatin1Encoding.
  438. % Writes code to declare and initialize enc_keys_, str_keys, and keys_.
  439. /wcdkeys    % <dict> wcdkeys -
  440.  {    % Write keys present in StandardEncoding or ISOLatin1Encoding,
  441.     % pushing other keys on the o-stack.
  442.    (static const charindex enc_keys_[] = {) wl
  443.    dup [ exch 0 exch
  444.     { pop decoding 1 index known
  445.        { decoding exch get ({) ws dup -8 bitshift wt
  446.      (,) ws 255 and wt (}, ) ws
  447.      1 add dup 5 mod 0 eq { (\n) ws } if
  448.        }
  449.        { exch }
  450.       ifelse
  451.     }
  452.    forall pop
  453.    ]
  454.    ({0,0}\n};) wl
  455.     % Write other keys.
  456.    (str_keys_) exch wsna
  457.     % Write the declaration for keys_.
  458.    (static const cfont_dict_keys keys_ = {) wl
  459.    (\tenc_keys_, countof\(enc_keys_\) - 1,) wl
  460.    (\t) ws dup length wt ( - \(countof\(enc_keys_\) - 1\), 0, ) ws
  461.    dup wpa (, ) ws wva () wl
  462.    (};) wl
  463.  } bind def
  464.  
  465. % Enumerate character dictionary values in the same order that
  466. % the keys appear in enc_keys_ and str_keys_.
  467. % <proc> is called with each value in turn.
  468. /cdforall    % <dict> <proc> cdforall -
  469.  { 2 copy
  470.     { decoding 3 index known
  471.        { 3 -1 roll pop exec }
  472.        { pop pop pop }
  473.       ifelse
  474.     }
  475.    /exec cvx 3 packedarray cvx
  476.    /forall cvx
  477.    5 -2 roll
  478.     { decoding 3 index known
  479.        { pop pop pop }
  480.        { 3 -1 roll pop exec }
  481.       ifelse
  482.     }
  483.    /exec cvx 3 packedarray cvx
  484.    /forall cvx
  485.    6 packedarray cvx exec
  486.  } bind def
  487.  
  488. % ------ Writers for special objects ------ %
  489.  
  490. /writespecial 10 dict dup begin
  491.  
  492.    /FontInfo { 0 wd } def
  493.  
  494.    /Private { 0 wd } def
  495.  
  496.    /CharStrings
  497.     { ({) wl
  498.       dup wcdkeys
  499.       (static const char values_[] = {) wl
  500.        { wsn } cdforall
  501.       (\t0\n};) wl
  502.       (\tcode = \(*pprocs->string_dict_create\)\(&) ws wt
  503.       (, &keys_, str_keys_, values_\);) wl
  504.       (\tif ( code < 0 ) return code;) wl
  505.       (}) wl
  506.     } bind def
  507.  
  508.    /Metrics
  509.     { ({) wl
  510.       dup wcdkeys
  511.       (static const ref_(float) values_[] = {) wl
  512.       dup { (\t) ws wnums () wl } cdforall
  513.       (\t0\n};) wl
  514.       (static const char lengths_[] = {) wl
  515.        { (\t) ws dup isnumber
  516.       { pop 0 }
  517.       { length 1 add }
  518.      ifelse wt (,) wl
  519.        } cdforall
  520.       (\t0\n};) wl
  521.       (\tcode = \(*pprocs->num_dict_create\)\(&) ws wt
  522.       (, &keys_, str_keys_, (const ref *)values_, lengths_\);) wl
  523.       (\tif ( code < 0 ) return code;) wl
  524.       (}) wl
  525.     } bind def
  526.  
  527.    /Metrics2 /Metrics load def
  528.  
  529.    /FDepVector pop    % (converted to a list of font names)
  530.  
  531. end def
  532.  
  533. % ------ The main program ------ %
  534.  
  535. % Construct an inverse dictionary of encodings.
  536. [ /StandardEncoding /ISOLatin1Encoding
  537.   /SymbolEncoding /DingbatsEncoding
  538.   /KanjiSubEncoding
  539. ]
  540. dup length dict begin
  541.  { mark exch dup { .findencoding exch def } stopped cleartomark
  542.  } forall
  543. currentdict end /encodingnames exch def
  544.  
  545. % Invert the StandardEncoding and ISOLatin1Encoding vectors.
  546. 512 dict begin
  547.   0 1 255 { dup ISOLatin1Encoding exch get exch 256 add def } for
  548.   0 1 255 { dup StandardEncoding exch get exch def } for
  549. currentdict end /decoding exch def
  550.  
  551. /writefont        % cfilename procname -> [writes the current font]
  552.  { (gsf_) exch concatstrings
  553.      /fontprocname exch def
  554.    /cfname exch def
  555.    /cfile cfname (w) file def
  556.  
  557. % Remove unwanted keys from the font.
  558.    currentfont dup length dict begin { def } forall
  559.     { /FID /MIDVector /CurMID } { currentdict exch undef } forall
  560.    /Font currentdict end def
  561.  
  562. % Replace the FDepVector with a list of font names.
  563.    Font /FDepVector .knownget
  564.     { [ exch { /FontName get } forall ]
  565.       Font /FDepVector 3 -1 roll put
  566.     }
  567.    if
  568.  
  569. % Find all the special objects we know about.
  570. % wo uses this to write out references to otherwise intractable objects.
  571.    /otherobjs writespecial length dict dup begin
  572.      writespecial
  573.       { pop Font 1 index .knownget { exch def } { pop } ifelse
  574.       }
  575.      forall
  576.    end def
  577.  
  578. % Define a dummy FontInfo, in case the font doesn't have one.
  579.    /FontInfo 0 dict def
  580.  
  581. % Write out the boilerplate.
  582.    Font begin
  583.    (/****************************************************************) wl
  584.    (   Portions of this file are subject to the following notice(s):) wl
  585.    systemdict /copyright get wl
  586.    FontInfo /Notice .knownget
  587.     { (----------------------------------------------------------------) wl wl
  588.     } if
  589.    (****************************************************************/) wl
  590.    () wl
  591.    (/* ) ws cfname ws ( */) wl
  592.    (/* This file was created by the ) ws product ws ( font2c utility. */) wl
  593.    () wl
  594.    (#undef DEBUG) wl
  595.    (#include "ccfont.h") wl
  596.    () wl
  597.  
  598. % Write the procedure prologue.
  599.    (#ifdef __PROTOTYPES__) wl
  600.    (int huge) wl
  601.    fontprocname ws ((const cfont_procs *pprocs, ref *pfont)) wl
  602.    (#else) wl
  603.    (int huge) wl
  604.    fontprocname ws ((pprocs, pfont) const cfont_procs *pprocs; ref *pfont;) wl
  605.    (#endif) wl
  606.    ({\tint code;) wl
  607.    (\tref Font;) wl
  608.    otherobjs
  609.     { exch pop (\tref ) ws wt (;) wl }
  610.    forall
  611.  
  612. % Write out the special objects.
  613.    otherobjs
  614.     { exch writespecial 2 index get exec
  615.     }
  616.    forall
  617.  
  618. % Write out the main font dictionary.
  619. % If possible, substitute the encoding name for the encoding;
  620. % PostScript code will fix this up.
  621.     { /Encoding /PrefEnc }
  622.     { Font 1 index .knownget
  623.        { encodingnames exch .knownget { def } { pop } ifelse }
  624.        { pop }
  625.       ifelse
  626.     }
  627.    forall
  628.    (Font) Font FontType 0 eq { 5 } { 1 } ifelse wd
  629.  
  630. % Finish the procedural initialization code.
  631.    (\t*pfont = Font;) wl
  632.    (\treturn 0;) wl
  633.    (}) wl
  634.    end                % Font
  635.  
  636.    cfile closefile
  637.  
  638.  } bind def
  639.  
  640. end def            % font2cdict
  641.  
  642. % Compute the procedure name from the font name.
  643. % Replace all non-alphanumeric characters with '_'.
  644. /makefontprocnamemap 256 string
  645.    0 1 255 { 2 copy 95 put pop } for
  646.    (0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz)
  647.     { 2 copy dup put pop } forall
  648. readonly def
  649. /makefontprocname    % <fontname> makefontprocname <procnamestring>
  650.  { dup length string cvs
  651.    dup length 1 sub -1 0
  652.     {        % Stack: string index
  653.       2 copy 2 copy get //makefontprocnamemap exch get put pop
  654.     }
  655.    for 
  656.  } def
  657.  
  658. /writefont { font2cdict begin writefont end } def
  659.  
  660. % If the program was invoked from the command line, run it now.
  661. [ shellarguments
  662.  { counttomark dup 2 eq exch 3 eq or
  663.     { counttomark -1 roll cvn
  664.       (Converting ) print dup =only ( font.\n) print flush
  665.       dup FontDirectory exch known { dup FontDirectory exch undef } if
  666.       findfont setfont
  667.       (FontName is ) print currentfont /FontName get ==only (.\n) print flush
  668.       counttomark 1 eq
  669.        {    % Construct the procedure name from the file name.
  670.          currentfont /FontName get makefontprocname
  671.        }
  672.       if
  673.       writefont
  674.       (Done.\n) print flush
  675.     }
  676.     { cleartomark
  677.       (Usage: font2c fontname cfilename.c [shortname]\n) print
  678.       ( e.g.: font2c Courier cour.c\n) print flush
  679.       mark
  680.     }
  681.    ifelse
  682.  }
  683. if pop
  684.